<?php

class Bridge_Transform
{
	public function execute($xml, $xsl, $string = false)
	{
		$objXsl = new DOMDocument( );
		$objXsl->load($xsl);
		
		$objProcessor = new XsltProcessor( );
		$objProcessor->registerPhpFunctions();
		$objProcessor->importStylesheet( $objXsl );
		
		if ( $string == true )
		{
			return $objProcessor->transformToXml($xml);	
		}
		else
		{
			return $objProcessor->transformToDoc($xml);
		}
	}
	
	public static function escapeXML($string)
	{
		$string = str_replace('&', '&amp;', $string);
		$string = str_replace('<', '&lt;', $string);
		$string = str_replace('>', '&gt;', $string);
		$string = str_replace('\'', '&#39;', $string);
		$string = str_replace('"', '&quot;', $string);
		
		$string = str_replace("&amp;#", "&#", $string);
		$string = str_replace("&amp;amp;", "&amp;", $string);
		
		return $string;
	}
}

class Bridge_Request
{
	public function getAttribute($key, $required = false, $default = null)
	{
		if ( array_key_exists($key, $_GET) )
		{
			$value = $_GET[$key];
			
			if ( $value != null )
			{
				return trim($value);
			}
		}
		
		if ( $required == true)
		{
			throw new Exception("required paramater '$key' missing");
		}
		elseif ( $default != null )
		{
			return $default;
		}
		else
		{
			return null;
		}
	}
	
	public function toXML()
	{
		$objXml = new DOMDocument();
		$objXml->loadXML("<request />");
		
		foreach ( $_GET as $key => $value )
		{
			$strSafeKey = strtolower( preg_replace( '/\W/', '_', $key ) );
			
			$objElement = $objXml->createElement($strSafeKey, Bridge_Transform::escapeXML($value));
			$objXml->documentElement->appendChild($objElement);
		}
		
		return $objXml;
	}
}

class Bridge_Response extends DOMDocument 
{
	public function __construct($name = "response")
	{
		parent::__construct();
		$this->loadXML("<$name />");
	}
	
	public function add($data, $wrapper = null)
	{
		$objNode = null;
		$objParent = null;
		
		// normalize the data coming in
				
		if ( $data instanceof DOMDocument )
		{
			$objNode = $data->documentElement;
		}
		elseif ( $data instanceof DOMNode )
		{
			$objNode = $data;
		}
		elseif ( $data instanceof SimpleXMLElement )
		{
			$objData = new DOMDocument();
			$objData->loadXML($data->asXML());
			$objNode = $objData->documentElement;
		}
		
		// import it
		
		$objImport = $this->importNode($objNode, true);
		
		// if a wrapper defined, then add it
		
		if ( $wrapper != null )
		{
			$objParent = $this->createElement($wrapper);
		}
		else
		{
			$objParent = $this->documentElement;
		}
		
		$objParent->appendChild($objImport);
	}
}

class Bridge_IP
{
	/**
	 * Strips periods and pads the subnets of an IP address to three spaces, 
	 * e.g., 144.37.1.23 = 144037001023, to make it easier to see if a remote 
	 * user's IP falls within a range
	 *
	 * @param string $strOriginal		original ip address
	 * @return string					address normalized with extra zeros
	 */
	
	private static function normalizeAddress($strOriginal)
	{
		$strNormalized = "";
		$arrAddress = explode( ".", $strOriginal );
		
		foreach ( $arrAddress as $subnet )
		{
			$strNormalized .= str_pad( $subnet, 3, "0", STR_PAD_LEFT );
		}
		
		return $strNormalized;
	}
	
	/**
	 * Is the ip address within the supplied ip range(s)
	 * For syntax/formatting of an ip range string, see config.xml.
	 * Basically, it's comma seperated ranges, where each range can use
	 * wildcard (*) or hyphen to seperate endpoints. 
	 *
	 * @param string $strAddress	ip address
	 * @param string $strRanges		ip ranges
	 * @return bool					true if in range, otherwise false
	 */
	
	public static function isLocal($strAddress, $strRanges)
	{
		$bolLocal = false;
		
		// normalize the remote address

		$iRemoteAddress = self::normalizeAddress( $strAddress );
		
		// get the local campus ip range from config

		$arrRange = array ( );
		$arrRange = explode( ",", $strRanges );
		
		// loop through ranges -- can be more than one

		foreach ( $arrRange as $range )
		{
			$range = str_replace( " ", "", $range );
			$iStart = null;
			$iEnd = null;
			
			// normalize the campus range

			if ( strpos( $range, "-" ) !== false )
			{
				// range expressed with start and stop addresses

				$arrLocalRange = explode( "-", $range );
				
				$iStart = self::normalizeAddress( $arrLocalRange[0] );
				$iEnd = self::normalizeAddress( $arrLocalRange[1] );
			}
			else
			{
				// range expressed with wildcards

				$strStart = str_replace( "*", "000", $range );
				$strEnd = str_replace( "*", "255", $range );
				
				$iStart = self::normalizeAddress( $strStart );
				$iEnd = self::normalizeAddress( $strEnd );
			
			}
			
			// see if remote address falls in between the campus range

			if ( $iRemoteAddress >= $iStart && $iRemoteAddress <= $iEnd )
			{
				$bolLocal = true;
			}
		}
		
		return $bolLocal;
	}
}

?>